package extend

import (
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
    _"fmt"
    "net/http"
    "encoding/json"
    "github.com/garyburd/redigo/redis"
)

var upGrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

//客户端 Client
type Client struct {
    //唯一id
    uuid string
    //用户id
    id string
    //连接的socket
    socket *websocket.Conn
	//发送的消息
	send chan []byte

}

//客户端管理
type ClientManager struct {
	//客户端 map 储存并管理所有的长连接client，在线的为true，不在的为false
	clients map[string]*Client
	//web端发送来的的message我们用broadcast来接收，并最后分发给所有的client
	broadcast chan []byte
	//新创建的长连接client
	register chan *Client
	//新注销的长连接client
	unregister chan *Client
}

type Message struct {
    //消息struct
    Sender    string `json:"sender,omitempty"`    //发送者
    Recipient string `json:"recipient,omitempty"` //接收者
    Content   string `json:"content,omitempty"`   //内容
}


//实例化客户端管理
var manager = ClientManager{
    broadcast:  make(chan []byte),
    register:   make(chan *Client),
    unregister: make(chan *Client),
    clients:    make(map[string]*Client),
}

var ReceiveMessage = make(chan []byte)


//初始化
func WebsocketInit(){
    //启动协程开启客户端管理中心
	go manager.start()
}


func LinkWebsocket(c *gin.Context){
    //接受客户端传过来的id
	id := c.DefaultQuery("id","0")

	//升级请求
	ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return
	}
    uuid := Uuid()
	//储存客户端数据
	client := &Client{uuid:uuid, id: id, socket: ws,send: make(chan []byte)}

	//注册一个新的链接
	manager.register <- client

    //启动协程收web端传过来的消息
    go client.read()
    //启动协程把消息返回给web端
    go client.write()
}


//客户端管理中心
func (manager *ClientManager) start() {
    for {
        select {
        case conn := <-manager.register:
			//注册客户端-加入管理者
            manager.clients[conn.uuid] = conn

            //将对应uuid与id加入redis
            r_key := conn.id
            rdb := Pool
            redisconn := rdb.Get()
            defer redisconn.Close()
            redisconn.Do("HSet","websocket:"+r_key,conn.uuid,conn.socket)

            //加入在线列表 
            redisconn.Do("HSet","online",conn.id,conn.id)

            // // redis 获取
            // v,_ := conn.Do("hGet",r_key)

            // v1,_ := redis.String(v,nil)
            // // string
            // fmt.Println(v1)
        case conn := <-manager.unregister:
			//关闭客户端
            log.Println("注销客户端"+conn.uuid)
            //删除对应reids
            r_key := conn.id
            rdb := Pool
            redisconn := rdb.Get()
            defer redisconn.Close()
            redisconn.Do("HDel","websocket:"+r_key,conn.uuid)
            //删除在线列表
            //先查询在线设备数  如果小于0则删除
            v,_ := redisconn.Do("Hlen","websocket:"+r_key)
            v1,_ := redis.Int(v,nil)
            log.Println(v1)
            if v1 <= 0 {
                redisconn.Do("HDel","online",conn.id)
            }
           
            delete(manager.clients, conn.uuid)
            //广播
        case message := <-manager.broadcast:
            manager.send(message)
        }
    }
}


//定义客户端管理的send方法-推送消息
func (manager *ClientManager) send(message []byte) {
    obj := &Message{}
    _ = json.Unmarshal(message, obj)
    for id, conn := range manager.clients {
        if obj.Sender == id {
            //continue
        }
		//接收者符合
        if obj.Recipient == conn.id || len(obj.Recipient) < 1 {
			ReturnRes := make(map[string]interface{})
			ReturnRes["data"] = obj.Content
			ReturnRes["code"] = 200
			ReturnRes["msg"] = "请求成功"
			jsonmsg,_ := json.Marshal(ReturnRes)
			var msg []byte = []byte(jsonmsg)
            conn.send <- msg
        }
    }
}


//发送消息
func (c *Client) write() {
    defer func() {
        log.Println("关闭3")
        _ = c.socket.Close()
    }()

    for {
        select {
        //从send里读消息
        case message, ok := <-c.send:
            //如果没有消息
            if !ok {
                log.Println("关闭4")
                _ = c.socket.WriteMessage(websocket.CloseMessage, []byte{})
                return
            }
            //有消息就写入，发送给web端
            _ = c.socket.WriteMessage(websocket.TextMessage, message)
            // log.Println(fmt.Sprintf("write Id:%s, msg:%s", c.id, string(message)))
        }
    }
}


//定义客户端结构体的read方法
func (c *Client) read() {
    defer func() {
        manager.unregister <- c
        _ = c.socket.Close()
    }()

    for {
        //读取消息
        _, str, err := c.socket.ReadMessage()
        //如果有错误信息，就注销这个连接然后关闭
        if err != nil {
            manager.unregister <- c
            _ = c.socket.Close()
            break
        }
		//接收客户端请求
		msg :=string(str[:])
		// log.Println(msg)
		 //将读取的消息发给对应的人
        message := &Message{}
		//发送者
        message.Sender = c.id
		//接收者
		message.Recipient = "5"
		//内容
		message.Content = msg 
        jsonMessage, _ := json.Marshal(&message)
        ReceiveMessage <- jsonMessage
        manager.broadcast <- jsonMessage
    }
}


//发送消息
func Notice(Sender string ,Recipient string ,res string){
    //将读取的消息发给对应的人
	message := &Message{}
	//发送者
	message.Sender = Sender
	//接收者
	message.Recipient = Recipient
	//内容
	message.Content = res
	jsonMessage, _ := json.Marshal(&message)
	manager.broadcast <- jsonMessage
}

//在线客户端
func  GetOnline() map[string]string{
    result_data := make(map[string]string)
    rdb := Pool
    redisconn := rdb.Get()
    defer redisconn.Close()
    reply, _ := redis.Strings(redisconn.Do("hkeys","online"))
    for _,v := range reply{
            result_data[v] = v
    }
    return result_data;
}


//利用chan接收消息
func GetReceiveMessage(){
    for {
        select{
            case msg := <-ReceiveMessage:
            obj := &Message{}
            _ = json.Unmarshal(msg, obj)
            log.Println(obj)
            log.Println(obj.Content)
        }
    }
}


// 外部调用
// func GetReceiveMessage(){
//     for {
//         select{
//             case msg := <-extend.ReceiveMessage:
//             obj := &extend.Message{}
//             _ = json.Unmarshal(msg, obj)
//             log.Println(obj)
//             log.Println(obj.Content)
//         }
//     }
// }
